#pragma once
#include <vector>
#include <algorithm>
#include <cmath>
#include "constants.h"
#include "data_io.h"

using namespace std;
// 模板函数的声明和定义都要写到头文件里

template <typename IterPoint>
bool any_of(IterPoint start, IterPoint end)
{
    for (; start != end; start++)
    {
        if (*start)
        {
            return true;
        }
    }
    return false;
}

template <typename IterPoint>
bool all_of(IterPoint start, IterPoint end)
{
    for (; start != end; start++)
    {
        if (!(*start))
        {
            return false;
        }
    }
    return true;
}

template <typename ValueType, typename IterPoint>
ValueType &max_of(IterPoint start, IterPoint end)
{
    IterPoint max_point = start;
    start++;
    for (int i = 1; start != end; start++, i++)
    {
        if ((*start) > (*max_point))
        {
            max_point = start;
        }
    }
    return *max_point;
}

template <typename ValueType, typename IterPoint>
ValueType &min_of(IterPoint start, IterPoint end)
{
    IterPoint min_point = start;
    start++;
    for (int i = 1; start != end; start++, i++)
    {
        if ((*start) < (*min_point))
        {
            min_point = start;
        }
    }
    return *min_point;
}

template <typename ValueType, typename IterPoint>
ValueType sum_of(IterPoint start, IterPoint end)
{
    ValueType ans = *start;
    for (start++; start != end; start++)
    {
        ans += (*start);
    }
    return ans;
}

template <typename IterPoint>
int arg_max_of(IterPoint start, IterPoint end)
{
    IterPoint max_point = start;
    start++;
    int max_i = 0;
    for (int i = 1; start != end; start++, i++)
    {
        if ((*start) > (*max_point))
        {
            max_point = start;
            max_i = i;
        }
    }
    return max_i;
}

template <typename IterPoint>
int arg_min_of(IterPoint start, IterPoint end)
{
    IterPoint min_point = start;
    start++;
    int min_i = 0;
    for (int i = 1; start != end; start++, i++)
    {
        if ((*start) < (*min_point))
        {
            min_point = start;
            min_i = i;
        }
    }
    return min_i;
}

template <typename IterPointTo, typename IterPointFrom>
void copy_arr(IterPointTo to, IterPointFrom from, int n)
{
    for (int i = 0; i < n; ++i, ++to, ++from)
    {
        (*to) = *(from);
    }
}

template <typename ValueType, typename IterPoint>
ValueType &rand_choice_of(IterPoint start, int n)
{
    return *(start + (rand() % n));
}

template <typename IterPoint>
vector<int> arg_sort(IterPoint start, int n, bool asc)
{
    vector<int> index(n, 0);
    for (int i = 0; i < n; ++i)
    {
        index[i] = i;
    }

    if (asc)
    {
        sort(index.begin(), index.end(), [&start](const int &a, const int &b)
             { return *(start + a) < *(start + b); });
    }
    else
    {
        sort(index.begin(), index.end(), [&start](const int &a, const int &b)
             { return *(start + a) > *(start + b); });
    }
    return index;
}

template <typename IterPoint>
void shuffle(IterPoint start, int n)
{
    for (; n > 1; n--)
    {
        swap(*(start + n - 1), *(start + rand() % n));
    }
}

class StdNormalizer
{
public:
    bool is_initeed = false;
    double mean = 0.0;
    double std = 1.0;

    int n = 0;
    double sum = 0.0;
    double square_sum = 0.0;

    StdNormalizer &add(double x);
    StdNormalizer &drop(double x);
    double transform(double x);
};

void process_overflow_t(TAssign *tassign);

double get_edge_site_score(const int &edge_site_bw, const int &site_bw_upper);
double get_center_site_score(const long long &center_site_bw);

void check_solution(AssignInfo &assign_info);
void show_score(AssignInfo &assign_info);

void show_center_cost_detail(TAssign *tassign);
void show_center_cost_detail(TAssign *tassign, int top_n);
void show_center_cost_detail(TAssign *tassign, bool show_stream_detail);
void show_center_cost_detail(TAssign *tassign, int site_id, int stream_id);
void show_center_cost_detail(TAssign *tassign, int site_id, int stream_id, int top_n, bool show_stream_detail);

void get_quantile_t(AssignInfo &assign_info, int (&edge_site_quantile_t)[MAX_N], int &center_site_quantile_t);
void assert(bool condition);